import numpy as np
import pandas as pd
from datetime import date
from app.Dao.FinanceDao.ExpenseDao import ExpenseDAO


class ExpenseServices:
    """支出业务逻辑层"""

    def __init__(self):
        self.expense_dao = ExpenseDAO()

    # 新增支出
    def add_expense(self, user_id, first_cate_id, second_cate_id, amount, expense_date, note=None, attach_path=None):
        """新增支出"""
        try:
            # 基础参数校验
            if not all([user_id, first_cate_id, second_cate_id, amount, expense_date]):
                return False, "必填参数缺失"

            # 金额合法性校验
            if float(amount) <= 0:
                return False, "支出金额必须大于0"

            success, result = self.expense_dao.create_expense(
                user_id, first_cate_id, second_cate_id, amount, expense_date,
                note=note, attach_path=attach_path
            )
            return (True, "支出记录添加成功") if success else (False, f"添加失败: {str(result)}")
        except Exception as e:
            return False, f"系统错误: {str(e)}"

    # 删除支出
    def delete_expense(self, expense_id, user_id):
        """
        删除支出记录（增加用户权限校验）
        :param expense_id: 支出记录ID
        :param user_id: 操作用户ID（用于权限验证）
        :return: (是否成功, 提示信息)
        """
        try:
            # 1. 验证记录是否存在且属于当前用户
            expense = self.expense_dao.get_expense_by_id(expense_id)
            if not expense:
                return False, "支出记录不存在"
            if expense.user_id != user_id:
                return False, "没有权限删除该记录"

            # 2. 执行删除操作
            success = self.expense_dao.delete_expense(expense_id)
            return (True, "支出记录已删除") if success else (False, "删除失败，请重试")
        except Exception as e:
            return False, f"删除失败: {str(e)}"

    # 更新支出
    def update_expense(self, expense_id, **kwargs):
        """
        更新支出记录
        :param expense_id: 支出记录ID
        :param user_id: 操作用户ID（用于权限验证）
        :param kwargs: 待更新字段（支持amount, date, first_cate_id, second_cate_id, note, attach_path）
        :return: (是否成功, 提示信息)
        """
        try:
            # 1. 验证记录归属权
            expense = self.expense_dao.get_expense_by_id(expense_id)
            if not expense:
                return False, "支出记录不存在"
            if expense.user_id != kwargs['user_id']:
                return False, "没有权限修改该记录"

            # 2. 参数预处理（如去除空格、金额校验）
            if 'note' in kwargs and kwargs['note'] is not None:
                kwargs['note'] = kwargs['note'].strip()
            if 'amount' in kwargs:
                try:
                    amount = float(kwargs['amount'])
                    if amount <= 0:
                        return False, "支出金额必须大于0"
                    kwargs['amount'] = amount
                except (ValueError, TypeError):
                    return False, "金额格式不正确"

            # 3. 执行更新操作
            updated_expense = self.expense_dao.update_expense(expense_id, **kwargs)
            return (True, "支出记录已更新") if updated_expense else (False, "更新失败，请重试")
        except Exception as e:
            return False, f"更新失败: {str(e)}"

    # 统计支出总额
    def get_expense_summary(self, user_id, year, month=None):
        """统计支出总额"""
        try:
            year_amount = self.expense_dao.get_expense_summary(user_id, year)
            res = [{'name': '年支出', 'value': year_amount}]

            if month:
                month_amount = self.expense_dao.get_expense_summary(user_id, year, month)
                res.insert(0, {'name': '月支出', 'value': month_amount})

            return True, res
        except Exception as e:
            return False, str(e)

    # 支出结构分析
    def get_expense_detail(self, user_id, first_cate_id=None, second_cate_id=None,
                           start_date: date = None, end_date: date = None):
        """按条件查询支出明细并聚合统计"""
        try:
            if not user_id:
                return False, "用户ID不能为空"

            # 获取数据并转换日期列
            df = self.expense_dao.get_expenses_with_categories(
                user_id=user_id,
                first_cate_id=first_cate_id,
                second_cate_id=second_cate_id
            )
            if df.empty:
                return True, []

            df['date'] = pd.to_datetime(df['date'])

            # 日期过滤
            if start_date and end_date:
                date_mask = (df['date'] >= pd.to_datetime(start_date)) & (df['date'] <= pd.to_datetime(end_date))
                df = df[date_mask]

            # 按分类层级聚合
            group_col = 'second_cate_name' if first_cate_id else 'first_cate_name'
            agg_df = df.groupby(group_col)['amount'].sum().reset_index()
            agg_df.rename(columns={group_col: 'name', 'amount': 'value'}, inplace=True)

            return True, agg_df.to_dict('records')

        except Exception as e:
            return False, f"查询支出明细失败：{str(e)}"

    # 每日支出明细
    def get_daily_expense_detail(self, user_id, target_date: date):
        """获取指定日期的支出明细数据"""
        try:
            if not (user_id and target_date):
                return False, "用户ID和目标日期不能为空"

            df = self.expense_dao.get_expenses_with_categories(user_id=user_id)
            if df.empty:
                return True, []

            # 日期过滤与格式处理
            df['date'] = pd.to_datetime(df['date']).dt.date
            daily_df = df[df['date'] == target_date].copy()
            daily_df['date'] = daily_df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))

            return True, daily_df.to_dict('records')

        except Exception as e:
            return False, f"获取日期明细失败：{str(e)}"

    # 获取所有一级分类
    def get_first_cate(self):
        """获取所有的一级分类"""
        return True, self.expense_dao.get_all_first_cates().to_dict('records')

    # 根据一级分类ID获取二级分类
    def get_second_cate_by_first_cate_id(self, first_cate_id):
        """根据一级分类id获取二级分类"""
        return True, self.expense_dao.get_second_cates_by_first_id(first_cate_id).to_dict('records')

    # 月度支出趋势
    def get_month_expense_detail(self, user_id, year: int, month: int):
        """获取某个月的支出数据"""
        # 参数校验
        if not (user_id and year and month):
            return False, "用户ID、年份和月份不能为空"

        df = self.expense_dao.get_expenses_with_categories(user_id=user_id)
        if df.empty:
            return True, []

        # 日期处理与过滤
        df['date'] = pd.to_datetime(df['date'])
        month_mask = (df['date'].dt.year == year) & (df['date'].dt.month == month)
        month_df = df[month_mask].copy()
        month_df['date'] = month_df['date'].dt.strftime('%Y-%m-%d')

        # 聚合计算
        agg_df = month_df.groupby('date')['amount'].sum().reset_index()
        x_axis = agg_df['date'].tolist()
        y_axis = agg_df['amount'].tolist()

        # 统计值计算
        total_days = len(agg_df)
        std_dev = float(agg_df['amount'].std()) if total_days > 1 else 0.0
        avg_amount = float(month_df['amount'].sum() / total_days) if total_days else 0.0

        return True, {
            'x_axis': x_axis,
            'y_axis': [{"name": "支出", "data": y_axis}],
            'std_dev': std_dev,
            'avg_amount': avg_amount
        }

    # 年度支出趋势
    def get_yearly_expense_trend(self, user_id, year: int):
        """获取年度每月支出趋势"""
        try:
            if not (user_id and year):
                return False, "用户ID和年份不能为空"

            trend_data = self.expense_dao.get_monthly_expense_trend(user_id, year)
            return True, {
                'months': [f"{month}月" for month in range(1, 13)],
                'amounts': trend_data,
                'total': sum(trend_data)
            }
        except Exception as e:
            return False, f"获取年度趋势失败：{str(e)}"
